#ifndef SERVER_MAIN_H
#define SERVER_MAIN_H



class server_main
{
public:
#define IF_IPV4	1
#define IF_IPV6 2
    server_main(boost::asio::io_service &io_service) :
        io_service_(io_service), 
		acceptor6_(io_service),
		acceptor4_(io_service),
		udp_socket4_(io_service),
		udp_socket6_(io_service)
    {
		config_file *cf = config_file::instance;

		if (cf->value_yes("listen_on_ipv4"))
		{
			boost::asio::socket_base::reuse_address option2(true);

			boost::asio::ip::tcp::endpoint end(tcp::v4(), TCP_Port);
			acceptor4_.open(end.protocol());
			acceptor4_.set_option(option2);
			acceptor4_.bind(end);
			acceptor4_.listen();

			start_auth_accept(IF_IPV4);

			udp::endpoint uend(udp::v4(), UDP_Port);
			udp_socket4_.open(uend.protocol());
			udp_socket4_.bind(uend);

			start_udp_keepalive_receivefrom(IF_IPV4);
		}
		if (cf->value_yes("listen_on_ipv6"))
		{
			boost::asio::ip::v6_only option(true);	
			boost::asio::socket_base::reuse_address option2(true);

			boost::asio::ip::tcp::endpoint end(tcp::v6(), TCP_Port);
			acceptor6_.open(end.protocol());
			acceptor6_.set_option(option);
			acceptor6_.set_option(option2);
			acceptor6_.bind(end);
			acceptor6_.listen();

			start_auth_accept(IF_IPV6);
		
			udp::endpoint uend(udp::v6(), UDP_Port);
			udp_socket6_.open(uend.protocol());
			udp_socket6_.set_option(option);
			udp_socket6_.bind(uend);

			start_udp_keepalive_receivefrom(IF_IPV6);
		}
    }
	void start_auth_accept(int if_ip)
	{
		authentication_ptr sp(new authentication(io_service_));
		if (if_ip == IF_IPV4)
			acceptor4_.async_accept(sp->get_socket(),
                               boost::bind(&server_main::handle_auth_accept, this, sp, if_ip,
                                           boost::asio::placeholders::error));
		if (if_ip == IF_IPV6)
			acceptor6_.async_accept(sp->get_socket(),
                               boost::bind(&server_main::handle_auth_accept, this, sp, if_ip,
                                           boost::asio::placeholders::error));
	}
    void handle_auth_accept(authentication_ptr auth_session, int if_ip,
                       const boost::system::error_code& error)
    {
        if (!error)
        {
            auth_session->start();
			start_auth_accept(if_ip);
        }
		else
		{
			cout << "error accept " << endl;
			start_auth_accept(if_ip);
		}
    }
	void start_udp_keepalive_receivefrom(int if_ip)
	{
		if (if_ip == IF_IPV4)
			udp_socket4_.async_receive_from(
				boost::asio::buffer(data4_, max_length), udp_sender_endpoint4_,
				boost::bind(&server_main::handle_udp_keepalive_receivefrom, this,
				  boost::asio::placeholders::error, if_ip,
				  boost::asio::placeholders::bytes_transferred));
		if (if_ip == IF_IPV6)
			udp_socket6_.async_receive_from(
				boost::asio::buffer(data6_, max_length), udp_sender_endpoint6_,
				boost::bind(&server_main::handle_udp_keepalive_receivefrom, this,
				  boost::asio::placeholders::error, if_ip,
				  boost::asio::placeholders::bytes_transferred));
	}
	void handle_udp_keepalive_receivefrom(const boost::system::error_code& error, int if_ip,
		size_t bytes_recvd)
	{
		unsigned char *data_;
		udp::socket *udp_socket_;
		udp::endpoint *udp_sender_endpoint_;
		if (if_ip == IF_IPV4)
		{
			udp_socket_ = &udp_socket4_;
			data_ = data4_;
			udp_sender_endpoint_ = &udp_sender_endpoint4_;
		}
		if (if_ip == IF_IPV6)
		{
			udp_socket_ = &udp_socket6_;
			data_ = data6_;
			udp_sender_endpoint_ = &udp_sender_endpoint6_;
		}
		//cout << "receive keep alive packet" << endl;
		if (!error && bytes_recvd > 0)
		{
			unsigned int sendlen = keep_alive::process_packet(data_, max_length, bytes_recvd);
			if (sendlen)
			{
				udp_socket_->async_send_to(
					boost::asio::buffer(data_, sendlen), *udp_sender_endpoint_,
					boost::bind(&server_main::handle_udp_keepalive_sendto, this,
					boost::asio::placeholders::error, if_ip,
					boost::asio::placeholders::bytes_transferred));
			}
			else
				start_udp_keepalive_receivefrom(if_ip);
		}
		else
		{
			start_udp_keepalive_receivefrom(if_ip);
		}
	}
	void handle_udp_keepalive_sendto(const boost::system::error_code& /*error*/, int if_ip,
		size_t /*bytes_sent*/)
	{
		start_udp_keepalive_receivefrom(if_ip);
	}


private:
    boost::asio::io_service &io_service_;
    tcp::acceptor acceptor6_;
	tcp::acceptor acceptor4_;

    udp::socket udp_socket4_;
	udp::socket udp_socket6_;
    udp::endpoint udp_sender_endpoint4_;
	udp::endpoint udp_sender_endpoint6_;
	enum { max_length = 1024 };
	unsigned char data4_[max_length];
	unsigned char data6_[max_length];
};


































#endif